/*
 *  lock_util.h, Copyright (c) 2016, mogujie.com
 *  All rights reserved
 *
 *  Created on: 2016年2月28日
 *      Author: yongxue@mogujie.com
 */

#ifndef THREAD_LOCK_UTIL_H_
#define THREAD_LOCK_UTIL_H_

#include <pthread.h>

#include "base/base.h"
#include "exception/util.h"

/**
 * 锁相关的命名空间
 */
namespace lock {

/**
 * 互斥量，对于以下接口的封装：
 * pthread_mutex_destroy(3), pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
 * pthread_mutex_lock(3), pthread_mutex_trylock(3), pthread_mutex_unlock(3)
 */
class MutexException: public except_util::Exception {
	public:
		MutexException(const string& msg, int code);
		~MutexException() = default;
};

class Mutex {
	public:
		/**
		 * 构造，初始化互斥量
		 */
		Mutex();

		/**
		 * 析构，释放资源
		 */
		~Mutex();

		/**
		 * 锁操作
		 */
		void lock();
		bool tryLock();
		void unlock();

		// cond中必须使用到该接口
		pthread_mutex_t* mutex() { return &m_mutex; }

	private:
		mutable pthread_mutex_t m_mutex;
};


class ReMutex {

};


/**********************************************************************************
 * 条件变量，实际是对于接口：
 * pthread_cond_broadcast(3), pthread_cond_signal(pthread_cond_t *cond);
 * pthread_cond_destroy(3), pthread_cond_init(3),
 * pthread_cond_timedwait(3), pthread_cond_wait(3)的封装
 */
class CondException: public except_util::Exception {
	public:
		CondException(const string& msg, int code);
		~CondException() = default;
};

class Cond {
	public:
		/**
		 * 构造，初始化条件变量
		 */
		Cond();

		/**
		 * 析构，初始化条件变量
		 */
		~Cond();

		/**
		 * 条件发生改变，发送信号，通知其他线程
		 * @return  属于void，基础接口，如果失败则直接抛出异常即可
		 */
		void signal();
		void broadcast();

		/**
		 * 解锁mutex，然后等待条件发生改变
		 * 采用模板，便于不同mutex封装的类的使用
		 */
		// 永久等待
		template<typename Mutex>
		void wait(IN const Mutex& mutex) const {
			// 原子操作unlock了mutex，然后等待；
			// 等待完成时，又原子执行了lock操作；
			int ret = pthread_cond_wait(&m_cond, mutex.mutex());
			if (ret != 0) {
				throw CondException("pthread_cond_wait error", errno);
			}
			return ;
		}

		// 超时等待
		template<typename Mutex>
		bool timedWait(IN const Mutex& mutex, IN int millsecond) const {
			timespec ts = abstime(millsecond);

			int ret = pthread_cond_timedwait(&m_cond, mutex.mutex(), &ts);
			if (ret == ETIMEDOUT) {
				return false;
			}
			if (ret != 0) {
				throw CondException("pthread_cond_timedwait error", errno);
			}
			return true;
		}

	protected:
		/**
		 * 绝对等待的时间
		 */
		timespec abstime(IN int millsecond) const;

	private:
		/**
		 * 线程条件变量
		 */
		mutable pthread_cond_t m_cond;
};

}


#endif /* THREAD_LOCK_UTIL_H_ */
